/*
* Author: Chris Seguin
*
* This software has been developed under the copyleft
* rules of the GNU General Public License. Please
* consult the GNU General Public License for more
* details about use and distribution of this software.
*/
package org.acm.seguin.pretty;
import java.util.StringTokenizer;
import java.util.Vector;
import org.acm.seguin.util.FileSettings;
import org.acm.seguin.util.MissingSettingsException;
/**
* Stores the java doc components
*
*@author Chris Seguin
*@date April 15, 1999
*/
public class JavaDocableImpl implements JavaDocable {
// Instance Variables
private Vector docs;
private boolean printed;
/**
* Constructor
*/
public JavaDocableImpl()
{
docs = new Vector();
printed = false;
}
/**
* Checks to see if it was printed
*
*@return true if it still needs to be printed
*/
public boolean isRequired()
{
return !printed;
}
/**
* Determines if the javadoc comments were printed
*
*@return The Printed value
*/
public boolean isPrinted()
{
return printed && (docs.size() > 0);
}
/**
* Allows you to add a java doc component
*
*@param component the component that can be added
*/
public void addJavaDocComponent(JavaDocComponent component)
{
if (component != null) {
docs.addElement(component);
}
}
/**
* Prints all the java doc components
*
*@param printData the print data
*/
public void printJavaDocComponents(PrintData printData)
{
printJavaDocComponents(printData, "");
}
/**
* Prints all the java doc components
*
*@param printData the print data
*@param order the order for the tags
*/
public void printJavaDocComponents(PrintData printData, String order)
{
// Saying that we are done
printed = true;
// Abort if there is nothing
if (docs.size() == 0) {
return;
}
// Adjust the spacing for the IDs
setLongest(getLongest());
// Make sure we are indented
if (!printData.isLineIndented()) {
printData.indent();
}
// Start the comment
int loop = printData.getJavadocStarCount() - 2;
printData.appendComment("/**", PrintData.JAVADOC_COMMENT);
for (int ndx = 0; ndx < loop; ndx++) {
printData.appendComment("*", PrintData.JAVADOC_COMMENT);
}
boolean onSingleLine = isOnSingleLine(printData);
if (!onSingleLine) {
printData.newline();
}
// Print all the components
print(printData, order, onSingleLine);
// Finish the comment
if (!onSingleLine) {
printData.indent();
}
printData.appendComment(" ", PrintData.JAVADOC_COMMENT);
for (int ndx = 0; ndx < loop; ndx++) {
printData.appendComment("*", PrintData.JAVADOC_COMMENT);
}
printData.appendComment("*/", PrintData.JAVADOC_COMMENT);
// Newline
printData.newline();
}
/**
* Makes sure all the java doc components are present
*/
public void finish() { }
/**
* Contains a particular item
*
*@param type the type we are looking for
*@return Description of the Returned Value
*/
public boolean contains(String type)
{
// Local Variables
int last = docs.size();
boolean found = false;
// Iterate through the components
for (int ndx = 0; ndx < last; ndx++) {
JavaDocComponent jdc = ((JavaDocComponent) docs.elementAt(ndx));
String typeName = jdc.getType();
if (typeName.equalsIgnoreCase(type)) {
jdc.setRequired(true);
found = true;
if (typeName.equals("param") || typeName.equals("return") ||
typeName.equals("exception") || typeName.equals("throws") ||
typeName.equals("")) {
return true;
}
}
}
// Not found
return found;
}
/**
* Contains a particular item
*
*@param type the type we are looking for
*@param id the id
*@return Description of the Returned Value
*/
public boolean contains(String type, String id)
{
// Local Variables
int last = docs.size();
// Iterate through the components
for (int ndx = 0; ndx < last; ndx++) {
Object next = docs.elementAt(ndx);
if (next instanceof NamedJavaDocComponent) {
NamedJavaDocComponent jdc = (NamedJavaDocComponent) next;
if ((jdc.getType().equalsIgnoreCase(type)) &&
(jdc.getID().equals(id))) {
jdc.setRequired(true);
return true;
}
}
}
// Not found
return false;
}
/**
* Make a required field
*
*@param tag the tag
*@param descr the default description
*/
public void require(String tag, String descr)
{
if (!contains(tag)) {
JavaDocComponent jdc = new JavaDocComponent();
jdc.setType(tag);
jdc.setDescription(descr);
addJavaDocComponent(jdc);
jdc.setRequired(true);
}
}
/**
* Make a required field
*
*@param tag the tag
*@param id the id
*@param descr the default description
*/
public void require(String tag, String id, String descr)
{
if (!contains(tag, id)) {
NamedJavaDocComponent jdc = new NamedJavaDocComponent();
jdc.setType(tag);
jdc.setID(id);
jdc.setDescription(descr);
addJavaDocComponent(jdc);
jdc.setRequired(true);
}
}
/**
* Set the longest id
*
*@param length the longest length
*/
private void setLongest(int length)
{
int last = docs.size();
for (int ndx = 0; ndx < last; ndx++) {
((JavaDocComponent) docs.elementAt(ndx)).setLongestLength(length);
}
}
/**
* Determine the maximum length
*
*@return the maximum length
*/
private int getLongest()
{
int longest = 0;
int last = docs.size();
for (int ndx = 0; ndx < last; ndx++) {
int next = ((JavaDocComponent) docs.elementAt(ndx)).getLongestLength();
longest = Math.max(next, longest);
}
return longest;
}
/**
* Determines if a particular component is a description
*
*@param current the current tag
*@return true if it is a description
*/
private boolean isDescription(JavaDocComponent current)
{
return current.getType().length() == 0;
}
/**
* Gets the TagRequired attribute of the JavaDocableImpl object
*
*@param tag Description of Parameter
*@return The TagRequired value
*/
private boolean isTagRequired(String tag)
{
try {
FileSettings bundle = FileSettings.getSettings("Refactory", "pretty");
bundle.getString(tag + ".descr");
return true;
}
catch (MissingSettingsException mse) {
return false;
}
}
/**
* Determines if the javadoc will fit on a single line
*
*@param printData the print data
*@return true if it can fit (and is allowed to fit) on a single
* line
*/
private boolean isOnSingleLine(PrintData printData)
{
if (!printData.isAllowSingleLineJavadoc()) {
return false;
}
if (docs.size() > 1) {
return false;
}
JavaDocComponent single = (JavaDocComponent) docs.elementAt(0);
if (!single.isDescription()) {
return false;
}
String text = single.getDescription();
if (text.length() > printData.getJavadocWordWrapMaximum()) {
return false;
}
text = text.toUpperCase();
if ((text.indexOf("<P>") >= 0) ||
(text.indexOf("<BR") >= 0) ||
(text.indexOf("<OL") >= 0) ||
(text.indexOf("<UL") >= 0)) {
return false;
}
return true;
}
/**
* Actually prints the components
*
*@param printData the print data
*@param order the order that stuff should be printed in
*/
private void print(PrintData printData, String order, boolean singleLine)
{
StringTokenizer tok = new StringTokenizer(order, ", \t\r\n");
// First print the description
printDescription(printData, singleLine);
// Now order the tags we know about
while (tok.hasMoreTokens()) {
String next = tok.nextToken();
boolean isRequired = isTagRequired(next);
tagPass("@" + next, printData, isRequired);
}
// Now print everything else
finalPass(printData);
}
/**
* Prints all the components that have a particular tag
*
*@param next the component
*@param printData the print data
*@param req Description of Parameter
*/
private void tagPass(String next, PrintData printData, boolean req)
{
JavaDocComponent current;
int last = docs.size();
for (int ndx = 0; ndx < last; ndx++) {
// Get the next element
current = ((JavaDocComponent) docs.elementAt(ndx));
// Does it go here
boolean now = next.equals(current.getType());
boolean required = !req || current.isRequired();
// If it is time, print it
if (now) {
if (required) {
printCurrentTag(current, printData, false, false);
}
else {
current.setPrinted(true);
}
}
}
}
/**
* Prints the description
*
*@param printData the print data
*/
private void printDescription(PrintData printData, boolean singleLine)
{
JavaDocComponent current;
int last = docs.size();
for (int ndx = 0; ndx < last; ndx++) {
// Get the next element
current = ((JavaDocComponent) docs.elementAt(ndx));
if (current.getType().equals("")) {
String descr = current.getDescription();
if (JavadocTokenizer.hasContent(descr)) {
printCurrentTag(current, printData, last == 1, singleLine);
}
current.setPrinted(true);
}
}
}
/**
* Prints all unknown tags
*
*@param printData the print data
*/
private void finalPass(PrintData printData)
{
JavaDocComponent current;
int last = docs.size();
for (int ndx = 0; ndx < last; ndx++) {
// Get the next element
current = ((JavaDocComponent) docs.elementAt(ndx));
// If it is time, print it
if (!current.isPrinted()) {
printCurrentTag(current, printData, false, false);
}
}
}
/**
* Prints the current tag
*
*@param current the tag
*@param printData the print data
*@param onlyDescription if it is the only tag
*/
private void printCurrentTag(JavaDocComponent current, PrintData printData, boolean onlyDescription, boolean singleLine)
{
// Print the element
printData.setCurrentIsSingle(singleLine);
current.print(printData);
printData.setCurrentIsSingle(false);
if (!onlyDescription && isDescription(current)) {
printSpaceAfterDescription(printData);
}
}
/**
* Prints a blank line after a description
*
*@param printData the print data
*/
private void printSpaceAfterDescription(PrintData printData)
{
printData.indent();
printData.appendComment(" *", PrintData.JAVADOC_COMMENT);
printData.newline();
}
}